﻿#include "souistd.h"
#include "res.mgr/SSkinPool.h"
#include "core/Sskin.h"
#include "SApp.h"
#include "helper/SDpiScale.h"
#include <map>

namespace SOUI {

    const wchar_t *BUILDIN_SKIN_NAMES[] = {
        L"_skin.sys.checkbox",
        L"_skin.sys.radio",
        L"_skin.sys.focuscheckbox",
        L"_skin.sys.focusradio",
        L"_skin.sys.btn",
        L"_skin.sys.scrollbar",
        L"_skin.sys.border",
        L"_skin.sys.dropbtn",
        L"_skin.sys.tree.toggle",
        L"_skin.sys.tree.checkbox",
        L"_skin.sys.tree.lines",
        L"_skin.sys.tab.page",
        L"_skin.sys.header",
        L"_skin.sys.split.vert",
        L"_skin.sys.split.horz",
        L"_skin.sys.prog.bkgnd",
        L"_skin.sys.prog.bar",
        L"_skin.sys.vert.prog.bkgnd",
        L"_skin.sys.vert.prog.bar",
        L"_skin.sys.slider.thumb",
        L"_skin.sys.btn.close",
        L"_skin.sys.btn.minimize",
        L"_skin.sys.btn.maxmize",
        L"_skin.sys.btn.restore",
        L"_skin.sys.menu.check",
        L"_skin.sys.menu.sep",
        L"_skin.sys.menu.arrow",
        L"_skin.sys.menu.border",
        L"_skin.sys.menu.skin",
        L"_skin.sys.icons",
        L"_skin.sys.wnd.bkgnd",
        L"_skin.sys.btn.prev",
        L"_skin.sys.btn.next",
        L"_skin.sys.spin.down",
        L"_skin.sys.spin.up",
    };
    
    
    /// <summary>
    ///
    /// </summary>
    class XSkinPoolImpl {
    
      public:
        ~XSkinPoolImpl() {
            for (auto &kv : m_skinObjs) {
            
                for (auto &skv : kv.second) {
                    if (skv.second) {
                        skv.second->Release();
                    }
                }
            }
            m_skinObjs.clear();
        }
      public:
        /**
           * GetSkin
           * @brief    获得与指定name匹配的SkinObj
           * @param    LPCWSTR strSkinName --    Name of Skin Object
           * @return   ISkinObj*  -- 找到的Skin Object
           * Describe
           */
        ISkinObj *GetSkin(const SStringW &strSkinName, int nScale) {
        
            for (auto const &kv : m_skinObjs) {
                if (kv.first <= nScale) {
                    auto iterSkin = kv.second.find(strSkinName);
                    if (iterSkin != kv.second.end()) {
                        return iterSkin->second;
                    }
                }
            }
            return nullptr;
        }
        
        /**
        * LoadSkins
        * @brief    从XML中加载Skin列表
        * @param    pugi::xml_node xmlNode --  描述SkinObj的XML表
        * @return   int -- 成功加载的SkinObj数量
        * Describe
        */
        int LoadSkins(pugi::xml_node xmlStyleRoot) {
            if (!xmlStyleRoot) {
                return FALSE;
            }
            
            int nLoaded = 0;
            SStringW strSkinName, strTypeName;
            
            pugi::xml_node xmlSkin = xmlStyleRoot.first_child();
            while (xmlSkin) {
                strTypeName = xmlSkin.name();
                strSkinName = xmlSkin.attribute(L"name").value();
                
                if (strSkinName.IsEmpty() || strTypeName.IsEmpty()) {
                    xmlSkin = xmlSkin.next_sibling();
                    continue;
                }
                
                ISkinObj *pSkin = SApplication::getSingleton().CreateSkinByName(strTypeName);
                if (pSkin) {
                    pSkin->InitFromXml(xmlSkin);
                    m_skinObjs[pSkin->GetScale()][strSkinName] = pSkin;
                    nLoaded++;
                } else {
                    // SASSERT_FMTW(FALSE, L"load skin error,type=%s,name=%s", strTypeName.c_str(), strSkinName.c_str());
                }
                xmlSkin = xmlSkin.next_sibling();
            }
            
            return nLoaded;
        }
        bool addSkin(const SStringW &strSkinName, ISkinObj *pSkinObj, int nScale) {
        
            auto &scaleSkinObjMap = m_skinObjs[nScale];
            auto iter = scaleSkinObjMap.find(strSkinName);
            if (iter != scaleSkinObjMap.end()) {
                return false;
            }
            
            scaleSkinObjMap[strSkinName] = pSkinObj;
            return true;
        }
      private:
        typedef std::map<SOUI::SStringW, ISkinObj *> ScaleSkinObjMap;
        std::map<int, ScaleSkinObjMap > m_skinObjs;
    };
    
    /// <summary>
    ///
    /// </summary>
    /// <param name="strSkinName"></param>
    /// <param name="nScale"></param>
    /// <returns></returns>
    
    XSkinPool::XSkinPool() {
        m_pImpl = new XSkinPoolImpl();
    }
    
    XSkinPool::~XSkinPool() {
        if (m_pImpl) {
            delete m_pImpl;
        }
    }
    
    ISkinObj *XSkinPool::GetSkin(const SStringW &strSkinName, int nScale) {
        if (m_pImpl) {
            return m_pImpl->GetSkin(strSkinName, nScale);
        }
        return nullptr;
    }
    
    int XSkinPool::LoadSkins(pugi::xml_node xmlNode) {
        if (m_pImpl) {
            return m_pImpl->LoadSkins(xmlNode);
        }
        return 0;
    }
    
    bool XSkinPool::addSkin(const SStringW &strSkinName, ISkinObj *pSkinObj, int nScale) {
        if (m_pImpl) {
            return m_pImpl->addSkin(strSkinName, pSkinObj, nScale);
        }
        return false;
    }
    
}//namespace SOUI